#include <iostream>
#include <functional>
using namespace std;

int add(int a, int b) {
    return a + b;
}
class divide {
    public:
        int operator()(int denominator, int divisor) {
            return denominator / divisor;
        }
};
class Calc {
    public: // 返回函数指针
        using ftype = int(*)(int, int); // 声明类型 的别名
        // 类型转换操作符
        operator ftype() {
            return ::add;
        }
        int add(int a, int b) {
            return a + b;
        }
};
// Calc 对象地址， Calc内部函数指针， 两个参数
int calc_function(Calc *obj, int (Calc::*func) (int a, int b), int data1, int data2) {
    return (obj->*func)(data1, data2);
}

int main(int argc, char const *argv[])
{
    // lambda 
    auto mod = [] (int a, int b) {
        return a % b;
    };
    cout << "mod(10, 3) = " << mod(10, 3) << endl; // lambda
    cout << "add(10, 2) = " << add(10, 2) << endl;  // 普通函数
    cout << "divide(10, 2) = " << divide()(10, 2) << endl; // 运算符重载

    Calc object;
    cout << object(10, 20) <<endl;
    cout << calc_function(&object, &Calc::add, 10, 20) << endl;

    // 以上几种调用对象虽然类型不同， 但是共享了一种调用形式
    // 使用std::function 可以将上述类型保存起来

    /*
        格式
        std::function<函数类型> = 可调用对象
        std:function<int(int, int)> a = add;
        std:function<int(int, int)> b = mod;
        std:function<int(int, int)> c = divide();
    
    */
    auto a = std::bind(add, 10, 20);

    cout << a() <<endl;

    // 未绑定参数可以使用命名空间的占位符替换
    auto b = std::bind(divide(), std::placeholders::_1, std::placeholders::_2);
    cout << b(10, 2) << endl;

    return 0;
}
